package com.filex.ads.network;


import android.content.Context;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.filex.ads.common.AdFormat;
import com.filex.ads.common.Preconditions;
import com.filex.ads.volley.RequestQueue;
import com.filex.ads.volley.Response;
import com.filex.ads.volley.VolleyError;

import java.lang.ref.WeakReference;

public class AdLoader {
    // to be implemented by external listener
    public interface Listener extends Response.ErrorListener {
        void onSuccess(AdResponse response);
    }

    private final WeakReference<Context> mContext;
    private final Listener mOriginalListener;

    private final AdRequest.Listener mAdListener;

    @NonNull
    private AdRequest mAdRequest;
    @Nullable
    protected AdResponse mAdResponse;
    @Nullable
    protected AdResponse mLastDeliveredResponse = null;

    private volatile boolean mRunning;
    private volatile boolean mFailed;

    @NonNull
    private Handler mHandler;

    public AdLoader(@NonNull final String url,
                    @NonNull final AdFormat adFormat,
                    @Nullable final String placementId,
                    @NonNull final Context context,
                    @NonNull final Listener listener) {
        Preconditions.checkArgument(!TextUtils.isEmpty(url));
        Preconditions.checkNotNull(adFormat);
        Preconditions.checkNotNull(context);
        Preconditions.checkNotNull(listener);

        mContext = new WeakReference<>(context);
        mOriginalListener = listener;

        mHandler = new Handler();

        mAdListener = new AdRequest.Listener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                mFailed = true;
                mRunning = false;
                deliverError(volleyError);
            }

            @Override
            public void onSuccessResponse(final AdResponse response) {
                mRunning = false;
                mAdResponse = response;
                deliverResponse(mAdResponse);
            }
        };

        mRunning = false;
        mFailed = false;
        mAdRequest = new AdRequest(url, adFormat, placementId, context, mAdListener);
    }


    @Nullable
    public AdRequest loadAd() {
        if (mRunning) {
            return mAdRequest;
        }
        if (mFailed) {
            // call back using handler to make sure it is always async.
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    deliverError(new FilexNetworkError(FilexNetworkError.Reason.UNSPECIFIED));
                }
            });
            return null;
        }
        return fetchAd(mAdRequest, mContext.get());
    }


    /**
     * Submits request to the networking library
     *
     * @param request will be sent to the networking library
     * @param context required by networking library
     * @return generic object Request to be used for cancel() if necessary
     */
    @Nullable
    private AdRequest fetchAd(@NonNull final AdRequest request,
                               @Nullable final Context context) {
        Preconditions.checkNotNull(request);

        if (context == null) {
            return null;
        }

        mRunning = true;
        RequestQueue requestQueue = Networking.getRequestQueue(context);
        mAdRequest = request;
        requestQueue.add(request);
        return request;
    }

    /**
     * Helper function to make callback
     *
     * @param volleyError error to be delivered
     */
    private void deliverError(@NonNull final VolleyError volleyError) {
        Preconditions.checkNotNull(volleyError);

        mLastDeliveredResponse = null;
        if (mOriginalListener != null) {
            if (volleyError instanceof FilexNetworkError) {
                mOriginalListener.onErrorResponse(volleyError);
            } else {
                mOriginalListener.onErrorResponse(new FilexNetworkError(volleyError.getMessage(),
                        volleyError.getCause(),
                        FilexNetworkError.Reason.UNSPECIFIED));
            }
        }
    }

    /**
     * Helper function to make 'success' callback
     *
     * @param adResponse valid {@link AdResponse} object
     */
    private void deliverResponse(@NonNull final AdResponse adResponse) {
        Preconditions.checkNotNull(adResponse);
        if (mOriginalListener != null) {
            mLastDeliveredResponse = adResponse;
            mOriginalListener.onSuccess(adResponse);
        }
    }

    public boolean isRunning() {
        return mRunning;
    }

    public boolean isFailed() {
        return mFailed;
    }
}
